﻿using System;
using System.Web;
using System.Web.Mvc;
using Actya.Core.Infrastructure;

namespace Actya.Web.Mvc.Helpers
{
	public static class ResourceExtensions
	{
		/// <summary>
		/// Include a reference to javascript file. You can call this multiple times per page but it will include the file
		/// only once. The path must start with "~/" when you want an absolute reference, otherwise the path is relative 
		/// from the ~/CmsContent directory.
		/// </summary>
		/// <param name="cmsHelper"></param>
		/// <param name="scriptPath">The virtual path of the javascript file (supports ~/)</param>
		/// <returns>
		/// A &lt;script&gt; tag that references the given javascript file. 
		/// An empty string is returned when the reference has been returned earlier during the current request.
		/// </returns>
		/// <remarks>Tracks the path reference in HttpContext.Items to prevent duplicates.</remarks>
		public static HtmlString ScriptInclude(this CmsHelper cmsHelper, string scriptPath)
		{
			if (IsAlreadyRegistered(cmsHelper, scriptPath))
			{
				return MvcHtmlString.Empty;
			}
			string resolvedScriptPath = ResolveAndRegisterPath(cmsHelper, scriptPath);
			return MvcHtmlString.Create(string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", resolvedScriptPath));
		}

		/// <summary>
		/// Include a reference to a css file.
		/// </summary>
		/// <param name="cmsHelper"></param>
		/// <param name="cssPath">The virtual path of the css file (supports ~/)</param>
		/// <returns>
		/// A &lt;link&gt; tag that references the given css file.
		/// An empty string is returned when the reference has been returned earlier during the current request.
		/// </returns>
		/// <remarks>Tracks the path reference in HttpContext.Items to prevent duplicates.</remarks>
		public static HtmlString CssLink(this CmsHelper cmsHelper, string cssPath)
		{
			if (IsAlreadyRegistered(cmsHelper, cssPath))
			{
				return MvcHtmlString.Empty;
			}
			string resolvedCssPath = ResolveAndRegisterPath(cmsHelper, cssPath);
			return MvcHtmlString.Create(string.Format("<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\">", resolvedCssPath));
		}

		/// <summary>
		/// Include a reference to a css file.
		/// </summary>
		/// <param name="cmsHelper"></param>
		/// <param name="cssPath">The virtual path of the css file (supports ~/)</param>
		/// <returns>
		/// A &lt;style&gt; block that has an @import reference to the given css file.
		/// An empty string is returned when the reference has been returned earlier during the current request.
		/// </returns>
		/// <remarks>Tracks the path reference in HttpContext.Items to prevent duplicates.</remarks>
		public static HtmlString CssImport(this CmsHelper cmsHelper, string cssPath)
		{
			if (IsAlreadyRegistered(cmsHelper, cssPath))
			{
				return MvcHtmlString.Empty;
			}
			string resolvedCssPath = ResolveAndRegisterPath(cmsHelper, cssPath);
			return MvcHtmlString.Create(string.Format("<style type=\"text/css\">@import url({0});</style>", resolvedCssPath));
		}

		/// <summary>
		/// Creates a proper url for a content reference. The path must start with "~/" when you want an absolute reference, otherwise the path is relative 
		/// from the ~/CmsContent directory.
		/// </summary>
		/// <param name="cmsHelper"></param>
		/// <param name="path"></param>
		/// <returns></returns>
		public static String Content(this CmsHelper cmsHelper, string path)
		{
			path = MakeAbsolutePath(path, cmsHelper.CmsContext);
			var urlHelper = new UrlHelper(cmsHelper.ViewContext.RequestContext);
			return urlHelper.Content(path);
		}

		private static bool IsAlreadyRegistered(CmsHelper cmsHelper, string virtualPath)
		{
			return cmsHelper.ViewContext.HttpContext.Items.Contains(virtualPath);
		}

		private static string ResolveAndRegisterPath(CmsHelper cmsHelper, string path)
		{
			var httpContext = cmsHelper.ViewContext.HttpContext;
			if (httpContext.Items.Contains(path))
			{
				throw new ArgumentException(string.Format("The path '{0}' is already registered.", path));
			}
			httpContext.Items.Add(path, String.Empty);
			path = MakeAbsolutePath(path, cmsHelper.CmsContext);
			var urlHelper = new UrlHelper(cmsHelper.ViewContext.RequestContext);
			return urlHelper.Content(path);
		}

		private static string MakeAbsolutePath(string path, ICmsContext cmsContext)
		{
			// when the path doesn't start with "~/" we're assuming that files are relative from the CmsContent directory.
			if (!path.StartsWith("~/"))
			{
				if (!path.StartsWith("/"))
				{
					path = "/" + path;
				}
				path = "~/CmsContent" + path;
			}
			return path;
		}
	}
}